#pragma once

#include "Misc/EngineEditorMacros.h"
#include "Object/Object.h"
#include "MaterialEditOperation.m.h"

class RMaterialGraphModel;

RCLASS()
class RMaterialEditOperation : public RObject
{
    ROBJECT

public:

    virtual void Undo(TSharedObjectPtr<RMaterialGraphModel> InGraph) {}
    virtual void Redo(TSharedObjectPtr<RMaterialGraphModel> InGraph) {}
    //combine this operation with the former operation
    //return true if this operation is combined to the former operation
    //if operation is combined, this operation will be useless
    virtual bool CombineTo(TSharedObjectPtr<RMaterialEditOperation> InFormerOperation) { return false; }

    virtual ~RMaterialEditOperation() = default;
};

RCLASS()
class RMaterialFunctionOperation : public RMaterialEditOperation
{
    ROBJECT

public:

    //the object that function might use
    //in most cases, it is empty
    RFIELD()
    TVector<RObjectPtr> Objects;

    TDelegate<void, TSharedObjectPtr<RMaterialGraphModel>> UndoFunction;

    TDelegate<void, TSharedObjectPtr<RMaterialGraphModel>> RedoFunction;

    virtual void Undo(TSharedObjectPtr<RMaterialGraphModel> InGraph) override
    {
        UndoFunction.ExecuteIfBound(InGraph);
    }
    virtual void Redo(TSharedObjectPtr<RMaterialGraphModel> InGraph) override
    {
        RedoFunction.ExecuteIfBound(InGraph);
    }
    
    virtual ~RMaterialFunctionOperation() = default;
};


//the operation to change the object field property
RCLASS()
class RMaterialChangeObjectPropertyOperation : public RMaterialEditOperation
{
    ROBJECT

public:

    void SetObjectAndOffset(
        TSharedObjectPtr<RObject> InObject
        ,int64_t InOffset
    );
    
    CAny OldValue;

    CAny NewValue;

    bool bCanCombine = false;
    
    virtual void Undo(TSharedObjectPtr<RMaterialGraphModel> InGraph) override;
    virtual void Redo(TSharedObjectPtr<RMaterialGraphModel> InGraph) override;
    virtual bool CombineTo(TSharedObjectPtr<RMaterialEditOperation> InFormerOperation) override;
protected:

    RFIELD()
    TSharedObjectPtr<RObject> Object;
    
    CProperty* Property=nullptr;
};